package com.isoft.aop;

import com.isoft.anno.SysControllerLogAnnotation;
import com.isoft.anno.SysServiceLogAnnotation;
import com.isoft.bean.UserContext;
import com.isoft.dao.SysLogDao;
import com.isoft.entity.SysLogContent;
import com.isoft.util.IPAddressUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

@Aspect
@Component
@EnableAsync
@Slf4j
public class SysLogAspect {
    @Autowired
    SysLogDao sysLogDao;
    @After("@annotation(com.isoft.anno.SysControllerLogAnnotation)")
    public void before(JoinPoint joinPoint) {
        log.error("后置通知");//之前是前置，但是得读完用户再赋值，所以只能这样了
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        handler(joinPoint,null,request, SysControllerLogAnnotation.class);
    }

    @AfterThrowing(pointcut = "@annotation(com.isoft.anno.SysServiceLogAnnotation)",throwing = "exp")
    public void afterThrowing(JoinPoint joinPoint, Throwable exp) {
        log.error("异常通知");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        handler(joinPoint,exp,request, SysServiceLogAnnotation.class);

    }

    /**
     * 负责拦截到Controller或者Service的方法后，将相关信息记录到日志文件 和  数据库
     * @param joinPoint
     * @param exp    afterThrowing() 调用handler时传参
     * @param request
     * @param annoClass  配置切点表达式的注解class
     */
    private void handler(JoinPoint joinPoint , Throwable exp , HttpServletRequest request , Class annoClass) {
        SysLogContent sysLog = new SysLogContent() ;
        Method method = ((MethodSignature)joinPoint.getSignature()).getMethod() ;
        Annotation annotation = method.getAnnotation(annoClass); // 获取到了@annotation的参数注解对象
        if(null != annotation) {
            if(annotation instanceof SysControllerLogAnnotation) {
                SysControllerLogAnnotation a = (SysControllerLogAnnotation) annotation;
                if (UserContext.getDescType() == null || UserContext.currentNum >1){
                    sysLog.setDesc(a.desc());
                }
                else{
                    UserContext.currentNum++;
                    sysLog.setDesc(UserContext.getDescType());
                }
//                  sysLog.setDesc(a.desc());
//     OK(原）       sysLog.setSysType(a.sysType().getName());
                System.out.println("=============================================================");
                System.out.println("AOP中CurrentUserType="+ UserContext.getCurrentUserType());
                if (UserContext.getCurrentUserType() == null){
                    UserContext.setCurrentUserType(a.sysType().getName()) ;
                    sysLog.setSystype(UserContext.getCurrentUserType());
                }
                else{ sysLog.setSystype(UserContext.getCurrentUserType());}
                sysLog.setOprtype(a.operateType().getName());
            } else if(annotation instanceof SysServiceLogAnnotation) {
                SysServiceLogAnnotation a = (SysServiceLogAnnotation) annotation;
                sysLog.setDesc(a.desc());
                sysLog.setSystype(a.sysType().getName());
                sysLog.setOprtype(a.operateType().getName());
            }
            sysLog.setRequesturl(request.getRequestURI() + "?" + getParams(joinPoint , method) );
            sysLog.setMethod(joinPoint.getTarget().getClass().getName() + "." +  joinPoint.getSignature().getName());
            sysLog.setIpaddress(IPAddressUtil.getIpAdrress(request));
            Date currentDate = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String formattedDate = sdf.format(currentDate);
            sysLog.setDodt(formattedDate);
            try {
                if(exp != null) {
                    sysLog.setDesc(sysLog.getDesc() + "-" + exp.getMessage());
                    sysLog.setLogtype(SysLogContent.LOGTYPE_EXCEPTION);
                } else {
                    sysLog.setLogtype(SysLogContent.LOGTYPE_NORMAL);
                }
                log.info("aop中的记录信息为 :" + sysLog.toString());
                // TODO: 写入数据库
                sysLogDao.addLog(sysLog);
            } catch (Exception e) {
                log.error(e.getMessage());
            }

        }
    }
    // 获取请求参数方法
    public String getParams(JoinPoint joinPoint , Method method){
        String params = "";
        // 请求的方法参数列表
        Object[] args = joinPoint.getArgs();
        // 请求的方法参数值
        StandardReflectionParameterNameDiscoverer u = new StandardReflectionParameterNameDiscoverer() ;
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            for (int i = 0; i < args.length; i++) {
                params += paramNames[i] + "=" + args[i] + "&";
            }
            params = params.substring(0 , params.length()-1) ;
        }
        return params ;
    }

}

